/* ==================================================================
* Copyright (c) 2024/11/15 SCNU LiuJunJie z-ken
* All rights reserved.
* fileName:	myalgor.cpp
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the xxx Group. and
* its contributors.
* 4. Neither the name of the Group nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Author,GROUP AND CONTRIBUTORS
* ===================================================================
* Author: LiuJunJie z-ken.
*/

#if !defined(MY_ALGOR_CPP)
#define MY_ALGOR_CPP

#include "myalgor.h"

void ParseAlgor::process(string productionFileName, string matchFilePath, string matchFileContentPath) {
    clean();

    initAttributeFilePath();
    // 读取文法配置文件
    lalrUtil1.formatAstTree.readConfig(attributeConfigFile);
    // 读取分析文法
    coreGenerateProductions(productionFileName);
    // LR1相关build
    coreGenerateLR();

    cout << "useAnalyseSheet*************************************" << endl;
    string matchFileName = matchFilePath;
    vector<string> analyseString = lalrUtil1.readStringLines(matchFileName);
    string matchFileContentName = matchFileContentPath;
    vector<string> contents = lalrUtil1.readStringLines(matchFileContentName);
    lalrUtil1.analyzeString(analyseString, contents);

    debug_analyse();
}

void ParseAlgor::processWithTokenParser(const string &productionFilePath, const string &programeFilePath,
                                        const string &jointFilePath) {

    // 先编译joint文件,生成CPP应用,cpp应用的名称为原本.cpp后缀更改为exe后缀
    int pos = jointFilePath.find_last_of('.');
    // 可执行程序名称
    string outPutFilePath = jointFilePath.substr(0, pos) + ".exe";

    string cmdGetExe = "g++ " + jointFilePath + " -o " + outPutFilePath;
    cout << jointFilePath << endl
         << outPutFilePath << endl;
    system(cmdGetExe.c_str());

    // 放置两个输出文件的位置,固定为当前工作目录,
    // 名称固定为match.txt和outputContent.txt,将这两个参数传递给joint.exe
    string matchFileOutPath = "./build-match.txt";
    string matchFileContentOutPath = "./build-outputContent.txt";
    string cmdGetMatchAndMatchContent =
            outPutFilePath + " " + programeFilePath + " " + matchFileOutPath + " " + matchFileContentOutPath;
    system(cmdGetMatchAndMatchContent.c_str());

    this->process(productionFilePath, matchFileOutPath, matchFileContentOutPath);
}

void ParseAlgor::processSingleMode(string productionFileName, string matchFilePath) {
    clean();

    // 初始化属性文法配置文件
    initAttributeFilePath();
    // 读取文法配置文件
    lalrUtil1.formatAstTree.readConfig(attributeConfigFile);
    // 核心函数执行
    // 读取分析文法
    coreGenerateProductions(productionFileName);
    // LR1相关build
    coreGenerateLR();

    cout << "useAnalyseSheet*************************************" << endl;
    string matchFileName = matchFilePath;
    // 单文件编码的规格是一个类型，一个内容
    vector<string> analyseStringAndContents = lalrUtil1.readStringLines(matchFileName);
    vector<string> analyseString, contents;
    for (int i = 0; i < analyseStringAndContents.size(); i++) {
        if (i % 2 == 0) {
            analyseString.push_back(analyseStringAndContents[i]);
        } else if (i % 2 == 1) {
            contents.push_back(analyseStringAndContents[i]);
        }
    }
    if (contents.size() != analyseString.size()) {
        cout << "读取的编码文件错误" << endl;
        return;
    }

    lalrUtil1.analyzeString(analyseString, contents);

    debug_analyse();
}

void ParseAlgor::processWithTokenParserSingleMode(const string &productionFilePath, const string &programeFilePath,
                                                  const string &jointFilePath) {
    // 初始化属性文法配置文件
    initAttributeFilePath();
    // 读取文法配置文件
    lalrUtil1.formatAstTree.readConfig(attributeConfigFile);

    // 先编译joint文件,生成CPP应用,cpp应用的名称为原本.cpp后缀更改为exe后缀
    int pos = jointFilePath.find_last_of('.');
    // 可执行程序名称
    string outPutFilePath = jointFilePath.substr(0, pos) + ".exe";

    string cmdGetExe = "g++ " + jointFilePath + " -o " + outPutFilePath;
    cout << jointFilePath << endl
         << outPutFilePath << endl;
    system(cmdGetExe.c_str());

    // 放置两个输出文件的位置,固定为当前工作目录,
    // 名称固定为match.txt和outputContent.txt,将这两个参数传递给joint.exe
    string matchFileOutPath = "./build-match.txt";
    string cmdGetMatchAndMatchContent =
            outPutFilePath + " " + programeFilePath + " " + matchFileOutPath;
    cout << cmdGetMatchAndMatchContent << endl;
    system(cmdGetMatchAndMatchContent.c_str());

    this->processSingleMode(productionFilePath, matchFileOutPath);
}

void ParseAlgor::processGenerateDfaAndAnalyseSheet(const string &productionFilePath) {
    clean();
    // 初始化属性文法配置文件
    initAttributeFilePath();
    // 读取文法配置文件
    lalrUtil1.formatAstTree.readConfig(attributeConfigFile);

    // 读取文法
    coreGenerateProductions(productionFilePath);
    // LR1相关build
    coreGenerateLR();
}

void ParseAlgor::processAnalyseProgramByAnalyser(const string &programeFilePath, const string &jointFilePath) {
    // ## 对生产的代码进行编译操作
    // 先编译joint文件,生成CPP应用,cpp应用的名称为原本.cpp后缀更改为exe后缀
    int pos = jointFilePath.find_last_of('.');
    // 可执行程序名称
//    string outPutFilePath = jointFilePath.substr(0, pos) + ".exe";
    string outPutFilePath = "split.exe";


    string cmdGetExe = "g++ " + jointFilePath + " -o " + outPutFilePath;
    cout << jointFilePath << endl
         << outPutFilePath << endl;
    system(cmdGetExe.c_str());

    // 放置两个输出文件的位置,固定为当前工作目录,
    // 名称固定为match.txt和outputContent.txt,将这两个参数传递给joint.exe
    string matchFileOutPath = "./build-match.txt";
    string cmdGetMatchAndMatchContent =
            outPutFilePath + " " + programeFilePath + " " + matchFileOutPath;
    cout << cmdGetMatchAndMatchContent << endl;
    system(cmdGetMatchAndMatchContent.c_str());

    // ## 进入正常的process逻辑
    // 执行任务
    cout << "useAnalyseSheet*************************************" << endl;
    string matchFileName = matchFileOutPath;
    // 单文件编码的规格是一个类型，一个内容
    vector<string> analyseStringAndContents = lalrUtil1.readStringLines(matchFileName);
    vector<string> analyseString, contents;
    for (int i = 0; i < analyseStringAndContents.size(); i++) {
        if (i % 2 == 0) {
            analyseString.push_back(analyseStringAndContents[i]);
        } else if (i % 2 == 1) {
            contents.push_back(analyseStringAndContents[i]);
        }
    }
    if (contents.size() != analyseString.size()) {
        cout << "读取的编码文件错误" << endl;
        return;
    }

    lalrUtil1.astTree.productionsName = this->productionsName; // 设置文法类型名称

    // 设置文法生成内容工具
    bool analyseRes = lalrUtil1.analyzeString(analyseString, contents);

    debug_analyse();

    if (analyseRes == false) {
        throw ANALYSE_ERROR();
    }
}

void ParseAlgor::processAnalyseProgramByEncodingFile(const string &encodingFilePath) {
    // ## 进入正常的process逻辑
    // 执行任务
    cout << "useAnalyseSheet*************************************" << endl;
    string matchFileName = encodingFilePath;
    // 单文件编码的规格是一个类型，一个内容
    vector<string> analyseStringAndContents = lalrUtil1.readStringLines(matchFileName);
    vector<string> analyseString, contents;
    for (int i = 0; i < analyseStringAndContents.size(); i++) {
        if (i % 2 == 0) {
            analyseString.push_back(analyseStringAndContents[i]);
        } else if (i % 2 == 1) {
            contents.push_back(analyseStringAndContents[i]);
        }
    }
    if (contents.size() != analyseString.size()) {
        cout << "读取的编码文件错误" << endl;
        return;
    }

    lalrUtil1.astTree.productionsName = this->productionsName; // 设置文法类型名称

    bool analyseRes = lalrUtil1.analyzeString(analyseString, contents);

    debug_analyse();

    if (analyseRes == false) {
        throw ANALYSE_ERROR();
    }

}

// 先回收后运行，此函数相当于创建新的lalrUtil
void ParseAlgor::clean() {
    // 创建一个引用 -- 方便使用
    ProductionUtil &ProductionUtil1 = this->lalrUtil1.ProductionUtil1;
    // 先回收后运行
    ProductionUtil1.recoveryForProduction();
    lalrUtil1.reocveryForLALR(); // 实际上封装 algor类之后,可以将非new内存进行不回收处理
}

void ParseAlgor::coreGenerateLR() {
    // LR1相关build
    lalrUtil1.setOnlyUseConfigAst(this->onlyUseConfigAst);
    lalrUtil1.astTree.productionsName = this->productionsName; // 设置文法类型名称
    lalrUtil1.buildDFA();
    cout << "LR1********************************************" << endl;
    lalrUtil1.showLR1_DFA();
    cout << "LALR**************************************" << endl;
    lalrUtil1.makeLALR();
    lalrUtil1.showLALR_DFA();
    cout << "Ordered_LALR**************************************" << endl;
    lalrUtil1.buildMappingAndDfaitemsForLALR();
    lalrUtil1.buildDFA_LALR_ordered();
    lalrUtil1.showStandardSecondSheet(lalrUtil1.DFA_LALR_ordered, lalrUtil1.DFA_item_s_LALR_ordered);
    // 分析表
    cout << "AnalyseSheet:**************************************" << endl;
    lalrUtil1.buildAnalyseSheet();
    lalrUtil1.showAnalyzeSheet();
}

void ParseAlgor::coreGenerateProductions(const string &productionFileName) {
    // 创建一个引用 -- 方便使用
    ProductionUtil &ProductionUtil1 = this->lalrUtil1.ProductionUtil1;
    // 读取文法
    ProductionUtil1.readProductions(productionFileName);
    // 文法build
    ProductionUtil1.buildNullAble();
    ProductionUtil1.buildFirst();
    ProductionUtil1.buildFollow();
    ProductionUtil1.buildSplitedIndex();
    ProductionUtil1.buildFirst_sSet();
}

bool ParseAlgor::isOnlyUseConfigAst() const {
    return onlyUseConfigAst;
}

void ParseAlgor::setOnlyUseConfigAst(bool useConfigAst) {
    ParseAlgor::onlyUseConfigAst = useConfigAst;
}

void ParseAlgor::debug_analyse() {


    cout << "AnalyseRecordList*************************************" << endl;
    lalrUtil1.showAnalyseRecordList();
    cout << "AnalyseTree*************************************" << endl;
    lalrUtil1.tree1.showTreeNodes();
    if (!this->onlyUseConfigAst) {
        cout << "AST*************************************" << endl;
        lalrUtil1.astTree.showAstTree();
    }
    cout << "AST-sheet2*************************" << endl;
    lalrUtil1.formatAstTree.showAstTree();
    cout << "FAC*************************" << endl;
    lalrUtil1.formatAstTree.showFac();
}


const string &ParseAlgor::getAttributeConfigFile() const {
    return attributeConfigFile;
}

void ParseAlgor::setAttributeConfigFile(const string &attributeConfigFile) {
    ParseAlgor::attributeConfigFile = attributeConfigFile;
}

#endif // MY_ALGOR_H
